/**
 * <p>文件名:		HashPostsRelatedTo.java</p>
 * <p>版权:		CopyrightTag</p>
 * <p>公司:		CompanyTag</p>
 * @author		周华彬(zhouhuabin@ctfo.com, zhou_hua_bin@163.com)
*/

package com.caits.lbs.framework.utils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * <p>HashPostsRelatedTo</p>
 * <p>一致性hash算法实现类</p>
 *  T类封装了机器节点的信息 ，如name、password、ip、port等   
 *
 * @author		周华彬(zhouhuabin@ctfo.com, zhou_hua_bin@163.com)
 * @version		0.0.0
 * <table style="border:1px solid gray;">
 * <tr>
 * <th width="100px">版本号</th><th width="100px">动作</th><th width="100px">修改人</th><th width="100px">修改时间</th>
 * </tr>
 * <!-- 以 Table 方式书写修改历史 -->
 * <tr>
 * <td>0.0.0</td><td>创建类</td><td>zhouhuabin</td><td>2015年4月14日 下午4:48:06</td>
 * </tr>
 * <tr>
 * <td>XXX</td><td>XXX</td><td>XXX</td><td>XXX</td>
 * </tr>
 * </table>
 */
public class HashPostsRelatedTo<T> {
	    /** 虚拟节点 map   */
	    private TreeMap<Long, T> nodes;
	    /** 真实机器节点    */
	    private List<T> shards;
	    /** 每个机器节点关联的虚拟节点个数 */
	    private final int NODE_NUM = 100;
	  
	    /**
	     * 构造器
	     * @param shards 
	     */
	    public HashPostsRelatedTo(List<T> shards) {  
	        super();  
	        this.shards = shards;  
	        init();  
	    }  
	  
	    /**
	     * 初始化一致性hash环 ,虚拟节点 map
	     */
	    private void init() { //    
	        nodes = new TreeMap<Long, T>();  
	        for (int i = 0; i != shards.size(); ++i) { // 每个真实机器节点都需要关联虚拟节点   
	            final T shardInfo = shards.get(i);  
	            for (int n = 0; n < NODE_NUM; n++)  
	                // 一个真实机器节点关联NODE_NUM个虚拟节点   
	                nodes.put(hash("SHARD-" + i + "-NODE-" + n), shardInfo);  
	        }  
	    }  
	  
	    /**
	     * 根据key返回该虚拟节点对应的真实机器节点的信息    
	     * @param key
	     * @return
	     */
	    public T getShardInfo(String key) { 
	    	SortedMap<Long, T> tail = nodes.tailMap(hash(key)); //大于等于就是 沿环的顺时针找到一个虚拟节点
	        if (tail.size() == 0) {  
	            return nodes.get(nodes.firstKey());  
	        }  
	        return tail.get(tail.firstKey()); // 返回该虚拟节点对应的真实机器节点的信息   
	    }  
	  
	    /** 
	     *  MurMurHash算法，是非加密HASH算法，性能很高， 
	     *  比传统的CRC32,MD5，SHA-1（这两个算法都是加密HASH算法，复杂度本身就很高，带来的性能上的损害也不可避免） 
	     *  等HASH算法要快很多，而且据说这个算法的碰撞率很低. 
	     *  http://murmurhash.googlepages.com/ 
	     */  
	    private Long hash(String key) {  
	        ByteBuffer buf = ByteBuffer.wrap(key.getBytes());  
	        int seed = 0x1234ABCD;  
	        ByteOrder byteOrder = buf.order();  
	        buf.order(ByteOrder.LITTLE_ENDIAN);  
	        long m = 0xc6a4a7935bd1e995L;  
	        int r = 47;  
	        long h = seed ^ (buf.remaining() * m);  
	  
	        long k;  
	        while (buf.remaining() >= 8) {  
	            k = buf.getLong();  
	            k *= m;  
	            k ^= k >>> r;  
	            k *= m;  
	            h ^= k;  
	            h *= m;  
	        }  
	  
	        if (buf.remaining() > 0) {  
	            ByteBuffer finish = ByteBuffer.allocate(8).order(  
	                    ByteOrder.LITTLE_ENDIAN);  
	            // for big-endian version, do this first:   
	            // finish.position(8-buf.remaining());   
	            finish.put(buf).rewind();  
	            h ^= finish.getLong();  
	            h *= m;  
	        }  
	  
	        h ^= h >>> r;  
	        h *= m;  
	        h ^= h >>> r;  
	  
	        buf.order(byteOrder);  
	        return h;  
	    }  
}
